package com.lintf.devdemo.utils;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

/**
 * @ system:Window
 * @ author:lin tingfeng
 * @ data:2022/10/24-14:02
 * @ package_name:com.lintf.devdemo.utils
 * @ project_name:DevDemo
 * @ desc:流处理工具类
 */
public class StreamUtil {

    public static void createStream() throws FileNotFoundException {
        /**
         * 1.1 使用Collection下的 stream() 和 parallelStream() 方法（最为常用）
         * parallelStream用在多线程并发时，而stream是单线程
         */
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();  //顺序流
        Stream<String> stringStream = list.parallelStream(); //并行流

        /**
         * 1.2 使用Arrays 中的 stream() 方法，将数组转成流
         */
        Integer[] nums = new Integer[]{10, 2, 3, 5};
        Stream<Integer> Integerstream = Arrays.stream(nums);

        /**
         * 1.3 使用Stream中的静态方法：of()、iterate()、generate()
         * iterate()、generate()方法可以创建无限流，可以通过limit()方法来限制数量。
         */
        Stream<Integer> TestStream = Stream.of(1, 2, 3, 4);
        Stream<Integer> TestStream2 = Stream.iterate(0, x -> x + 2);
        Stream<Integer> TestStream3 = Stream.generate(() -> new Random().nextInt(10));
        Stream<Integer> TestStream4 = Stream.iterate(0, x -> x + 2).limit(10);

        /**
         * 1.4 使用 BufferedReader.lines() 方法，将每行内容转成流
         */
        BufferedReader reader = new BufferedReader(new FileReader("F:\\test_stream.txt"));
        Stream<String> lineStream = reader.lines();
        //上面可以写成一行
        Stream<String> lineStream2 = new BufferedReader(new FileReader("F:\\test_stream.txt")).lines();

        /**
         * 1.5 使用 Pattern.splitAsStream() 方法，将字符串分隔成流
         */
        Pattern pattern = Pattern.compile(",");
        Stream<String> stringStream2 = pattern.splitAsStream("a,b,c,d");
    }

    public static void middleOption() {
        /**
         * 2.1 筛选与切片
         * filter： 过滤流中的某些元素
         * limit(n)： 获取n个元素，限制获取元素的个数
         * skip(n)： 跳过n元素，配合limit(n)可实现分页
         * distinct： 通过流中元素的 hashCode() 和 equals() 去除重复元素
         */
        Stream<Integer> stream = Stream.of(6, 6, 6, 12, 22, 12, 213, 111, 7, 9, 10);
        Stream<Integer> streamFilter = stream.filter(item -> item > 10) // 12 22 12 213 111
                .distinct() //12 22 213 111
                .skip(2) //213 111
                .limit(1);//213
        streamFilter.forEach(System.out::println);

        /**
         * 2.2 映射
         * map：接收一个函数作为参数，(常为lambda表达式)该函数会被应用到每个元素上，并将其映射成一个新的元素。
         * flatMap：接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流。
         *
         * flatMap和map的区别
         * 使用flatMap方法的效果是，各个数组并不是分别映射一个流，而是映射成流的内容。但是这个解释有点抽象
         */
        List<String> list = Arrays.asList("String", "f,g,h");
        Stream<String> stringStream = list.stream().map(s -> s.replaceAll(",", ""));//String fgh
        Stream<String> stringStream2 = list.stream().flatMap(s -> {
            String[] split = s.split(",");
            Stream<String> testStream = Arrays.stream(split);
            return testStream;
        });//String f g h
        stringStream2.forEach(System.out::println);

        /**
         * 2.3 排序
         * sorted()：自然排序，流中元素需实现Comparable接口
         */
        // 这里String类已经实现了Comparable接口
        List<String> sortList = Arrays.asList("tt", "er", "Ad");
        sortList.stream().sorted().forEach(System.out::println);//Ad er tt
        // 自定义Comparator排序器 自定义排序：先按姓名升序，姓名相同则按年龄升序
        Person p1 = new Person("zhangsan", 26);
        Person p2 = new Person("zhangsan", 22);
        Person p3 = new Person("wangwu", 23);
        List<Person> personList = Arrays.asList(p1, p2, p3);
        personList.stream().sorted((o1, o2) -> {
            if (o1.getName().equals(o2.getName())) {
                return o1.getAge() - o2.getAge();
            } else {
                return o1.getName().compareTo(o2.getName());
            }
        }).forEach(System.out::println);

        /**
         * 2.4 消费
         * peek：如同于map，能得到流中的每一个元素。但map接收的是一个Function表达式，有返回值；而peek接收的是Consumer表达式，没有返回值。
         */
        Person pp1 = new Person("zhangsan", 26);
        Person pp2 = new Person("lisi", 22);
        Person pp3 = new Person("wangwu", 23);
        List<Person> personListList = Arrays.asList(pp1, pp2, pp3);
        personListList.stream().peek(item -> item.setAge(100)).forEach(System.out::println);
    }

    public static void main(String[] args) throws FileNotFoundException {
        /**
         * flatMap和map的区别
         * 例子:给定单词列表 [“Hello”,“World”], 现在想返回列表[“H”,“e”,“l”,“o”,“W”,“r”,“d”]
         */
        String[] mapWords = new String[]{"Hello", "World"};
        List<String[]> mapList = Arrays.stream(mapWords)
                .map(word -> word.split(""))
                .distinct()
                .collect(toList());
        mapList.forEach(System.out::print);
        System.out.println("\n=================================================");
        String[] flatMapWords = new String[]{"Hello", "World"};
        List<String> flatMapList = Arrays.stream(flatMapWords)
                .map(word -> word.split(""))
                .flatMap(Arrays::stream)
                .distinct()
                .collect(toList());
        flatMapList.forEach(System.out::print);//HeloWrd
    }

}
